package com.atguigu.tingshu.user.service.impl;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import com.atguigu.tingshu.album.client.TrackInfoFeignClient;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.rabbit.constant.MqConst;
import com.atguigu.tingshu.common.rabbit.service.RabbitService;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.user.*;
import com.atguigu.tingshu.user.mapper.*;
import com.atguigu.tingshu.user.service.UserInfoService;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.atguigu.tingshu.vo.user.UserPaidRecordVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.service.WxService;
import org.joda.time.LocalDateTime;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements UserInfoService {

    @Autowired
    private UserInfoMapper userInfoMapper;
    @Autowired
    private WxMaService wxMaService;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private RabbitService rabbitService;
    @Autowired
    private UserPaidAlbumMapper userPaidAlbumMapper;
    @Autowired
    private UserPaidTrackMapper userPaidTrackMapper;
    @Autowired
    private TrackInfoFeignClient trackInfoFeignClient;
    @Autowired
    private VipServiceConfigMapper vipServiceConfigMapper;
    @Autowired
    private UserVipServiceMapper userVipServiceMapper;

    /**
     * 微信登录方法
     * 该方法通过微信提供的code换取session信息，并处理用户信息，生成token，完成登录过程
     *
     * @param code 微信登录时获取的code，用于换取session信息
     * @return 返回包含token的Map对象，用于后续的接口调用
     */
    @Override
    public Map<String, Object> wxLogin(String code) {
        // 创建一个HashMap用于存储返回的数据
        HashMap<String, Object> map = new HashMap<>();
        // 初始化微信JSCode换取Session结果对象
        WxMaJscode2SessionResult wxMaJscode2SessionResult = null;
        // 尝试通过微信code换取session信息
        try {
            wxMaJscode2SessionResult = wxMaService.jsCode2SessionInfo(code);
        } catch (WxErrorException e) {
            // 如果发生错误，抛出运行时异常
            throw new RuntimeException(e);
        }
        // 获取用户的openid
        String openid = wxMaJscode2SessionResult.getOpenid();
        // 根据openid查询用户信息
        UserInfo userInfo = userInfoMapper.selectOne(new LambdaQueryWrapper<UserInfo>().eq(UserInfo::getWxOpenId, openid));
        // 如果用户信息为空，表示是新用户，进行注册操作
        if (null == userInfo) {
            // 初始化新用户信息
            userInfo = new UserInfo();
            // 设置用户昵称，使用随机UUID确保唯一性
            userInfo.setNickname("用户" + UUID.randomUUID().toString().replaceAll("-", ""));
            // 关联微信openid
            userInfo.setWxOpenId(openid);
            // 设置默认头像
            userInfo.setAvatarUrl("https://oss.aliyuncs.com/aliyun_id_photo_bucket/default_handsome.jpg");
            // 插入用户信息到数据库
            userInfoMapper.insert(userInfo);
            // 发送消息到 RabbitMQ，通知用户注册
            rabbitService.sendMessage(MqConst.EXCHANGE_USER, MqConst.ROUTING_USER_REGISTER, userInfo.getId());
        }
        // 生成用户登录token，使用随机UUID确保唯一性
        String token = UUID.randomUUID().toString().replaceAll("-", "");
        // 将用户信息存入Redis，关联token，设置过期时间
        redisTemplate.opsForValue().set(RedisConstant.USER_LOGIN_KEY_PREFIX + token, userInfo, RedisConstant.USER_LOGIN_KEY_TIMEOUT, TimeUnit.SECONDS);
        // 将token放入返回的Map中
        map.put("token", token);
        // 返回包含token的Map对象
        return map;
    }

    /**
     * 根据用户ID获取用户信息视图对象
     *
     * @param userId 用户ID，用于查询用户信息
     * @return UserInfoVo 用户信息视图对象，包含用户的基本信息
     */
    @Override
    public UserInfoVo getUserInfoVoByUserId(Long userId) {
        // 创建一个用户信息视图对象实例
        UserInfoVo userInfoVo = new UserInfoVo();
        // 通过用户ID从数据库中查询用户信息
        UserInfo userInfo = userInfoMapper.selectById(userId);
        // 将查询到的用户信息复制到视图对象中
        BeanUtils.copyProperties(userInfo, userInfoVo);
        // 返回填充好的用户信息视图对象
        return userInfoVo;
    }

    /**
     * 保存用户付费记录
     * 根据不同的订单项类型（专辑、音轨、VIP服务），处理相应的付费记录
     *
     * @param userPaidRecordVo 用户付费记录的视图对象，包含订单信息和用户信息
     * @return 插入或更新记录的结果，成功返回1，失败返回0
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int savePaidRecord(UserPaidRecordVo userPaidRecordVo) {
        int result = 0;
        // 根据订单项类型处理不同的付费记录
        if (SystemConstant.ORDER_ITEM_TYPE_ALBUM.equals(userPaidRecordVo.getItemType())){
            // 检查是否存在相同的专辑付费记录
            UserPaidAlbum userPaidAlbum = userPaidAlbumMapper.selectOne(new LambdaQueryWrapper<UserPaidAlbum>().eq(UserPaidAlbum::getOrderNo, userPaidRecordVo.getOrderNo()).eq(UserPaidAlbum::getUserId, userPaidRecordVo.getUserId()));
            if (null != userPaidAlbum){
                return result;
            }
            // 创建并插入新的专辑付费记录
            userPaidAlbum = new UserPaidAlbum();
            userPaidAlbum.setAlbumId(userPaidRecordVo.getItemIdList().get(0));
            userPaidAlbum.setOrderNo(userPaidRecordVo.getOrderNo());
            userPaidAlbum.setUserId(userPaidRecordVo.getUserId());
            return  result+=userPaidAlbumMapper.insert(userPaidAlbum);

        }else if (SystemConstant.ORDER_ITEM_TYPE_TRACK.equals(userPaidRecordVo.getItemType())){
            List<Long> itemIdList = userPaidRecordVo.getItemIdList();
            // 获取音轨信息并检查用户是否已购买
            Result<TrackInfo> trackInfoResult = trackInfoFeignClient.getTrackInfo(userPaidRecordVo.getItemIdList().get(0));
            Assert.notNull(trackInfoResult,"远程调用失败");
            TrackInfo trackInfo = trackInfoResult.getData();
            List<Long> userPaidTrackList = userPaidTrackMapper.selectList(new LambdaQueryWrapper<UserPaidTrack>().eq(UserPaidTrack::getUserId, userPaidRecordVo.getUserId()).in(UserPaidTrack::getTrackId, itemIdList)).stream().map(UserPaidTrack::getTrackId).collect(Collectors.toList());
            // 插入新的音轨付费记录
            for (Long trackId : itemIdList) {
                if (userPaidTrackList.contains(trackId)){
                    log.warn("退款"+trackId);
                }else {
                    UserPaidTrack userPaidTrack = new UserPaidTrack();
                    userPaidTrack.setUserId(userPaidRecordVo.getUserId());
                    userPaidTrack.setTrackId(trackId);
                    userPaidTrack.setOrderNo(userPaidRecordVo.getOrderNo());
                    userPaidTrack.setAlbumId(trackInfo.getAlbumId());
                    result += userPaidTrackMapper.insert(userPaidTrack);
                }
            }
            return result;
        }else {
            // 处理VIP服务的付费记录
            Long vipServiceConfigId = userPaidRecordVo.getItemIdList().get(0);
            VipServiceConfig vipServiceConfig = vipServiceConfigMapper.selectById(vipServiceConfigId);
            Integer serviceMonth = vipServiceConfig.getServiceMonth();
            UserVipService userVipService = new UserVipService();
            Date vipExpireTime = new Date();
            UserInfo userInfo = userInfoMapper.selectById(userPaidRecordVo.getUserId());
            // 计算VIP服务的到期时间
            if (1 == userInfo.getIsVip()&&userInfo.getVipExpireTime().after(new Date())){
                vipExpireTime = userInfo.getVipExpireTime();
                LocalDateTime localDateTime = new LocalDateTime(vipExpireTime).plusMinutes(serviceMonth);
                //localDateTime.plusMonths(serviceMonth);
                //userVipService.setExpireTime(localDateTime.toDate());
                vipExpireTime = localDateTime.toDate();
            }else {
                vipExpireTime = new LocalDateTime(vipExpireTime).plusMonths(serviceMonth).toDate();
            }
            // 更新用户VIP服务记录和用户信息
            userVipService.setUserId(userPaidRecordVo.getUserId());
            userVipService.setOrderNo(userPaidRecordVo.getOrderNo());
            userVipService.setStartTime(new Date());
            userVipService.setExpireTime(vipExpireTime);
            result+=userVipServiceMapper.insert(userVipService);
            userInfo.setIsVip(1);
            userInfo.setVipExpireTime(vipExpireTime);
            result+=userInfoMapper.updateById(userInfo);

        }
        return result;
    }

    /**
     * 返回用户购买的专辑声音id集合
     *
     * @param userId
     * @param albumId
     * @return
     */
    @Override
    public List<Long> findUserPaidTrackList(Long userId, Long albumId) {
        return userPaidTrackMapper.selectList(new LambdaQueryWrapper<UserPaidTrack>()
                        .eq(UserPaidTrack::getAlbumId, albumId).eq(UserPaidTrack::getUserId, userId))
                .stream().map(UserPaidTrack::getTrackId).collect(Collectors.toList());
    }

    /**
     * 判断用户是否购买过专辑
     *
     * @param albumId
     * @param userId
     * @return
     */
    @Override
    public Boolean isPaidAlbum(Long albumId, Long userId) {
        Long count = userPaidAlbumMapper.selectCount(new LambdaQueryWrapper<UserPaidAlbum>().eq(UserPaidAlbum::getAlbumId, albumId).eq(UserPaidAlbum::getUserId, userId));
        if (count > 0) {
            return true;
        }
        return false;
    }

    /**
     * 根据用户ID和专辑ID检查音轨是否已付费
     *
     * @param userId      用户ID
     * @param albumId     专辑ID
     * @param trackIdList 音轨ID列表
     * @return 返回一个映射，键为音轨ID，值为1表示已付费，值为0表示未付费
     */
    @Override
    public Map<Long, Integer> userIsPaidTrack(Long userId, Long albumId, List<Long> trackIdList) {
        // 初始化一个HashMap用于存储音轨ID和其对应的付费状态
        HashMap<Long, Integer> map = new HashMap<>();

        // 查询用户是否已付费该专辑
        UserPaidAlbum userPaidAlbum = userPaidAlbumMapper.selectOne(new LambdaQueryWrapper<UserPaidAlbum>().eq(UserPaidAlbum::getUserId, userId).eq(UserPaidAlbum::getId, albumId));

        // 如果用户已付费该专辑，则所有音轨视为已付费
        if (null != userPaidAlbum) {
            return trackIdList.stream().collect(Collectors.toMap(trackId -> trackId, trackId -> 1));
        } else {
            // 构造查询条件，用于查询用户在该专辑中已付费的音轨
            LambdaQueryWrapper<UserPaidTrack> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(UserPaidTrack::getUserId, userId).in(UserPaidTrack::getTrackId, trackIdList).eq(UserPaidTrack::getAlbumId, albumId);

            // 获取用户已付费的音轨ID列表
            List<Long> userPaidTrackIdList = userPaidTrackMapper.selectList(queryWrapper).stream().map(UserPaidTrack::getTrackId).collect(Collectors.toList());

            // 遍历音轨ID列表，根据用户已付费的音轨ID列表更新映射
            for (Long trackId : trackIdList) {
                if (userPaidTrackIdList.contains(trackId)) {
                    map.put(trackId, 1);
                } else {
                    map.put(trackId, 0);
                }
            }
        }

        // 返回存储音轨ID和付费状态的映射
        return map;
    }
}
